from collections import defaultdict
import numpy as np
from typing import List, Dict, Tuple, Optional

class Scorer:
    """
    负责对匹配结果进行评分、排序和验证，以找出最佳匹配。
    """
    def __init__(self, config: Dict):
        """
        初始化评分器。
        """
        self.min_votes = config['min_votes']
        self.min_ratio = config['min_ratio']
        self.thresholds = config['verification_thresholds']
        # 新增：读取拒绝阈值配置
        self.rejection_thresholds = config.get('rejection_thresholds', {})
        self.max_votes_for_rejection = self.rejection_thresholds.get('max_votes_for_rejection', 15)

    def find_best_match(self, query_fingerprints: List[Tuple[str, int]], db_matches: Dict[str, List[Tuple[int, int]]]) -> Tuple[Optional[Dict], Dict]:
        """
        寻找最佳匹配歌曲的主方法。
        """
        diagnostics = {'histogram': {}}
        if not db_matches:
            return None, diagnostics

        histogram = self._build_offset_histogram(query_fingerprints, db_matches)
        diagnostics['histogram'] = histogram

        best_candidate = self._detect_peak_match(histogram)

        # 新增：如果最高票数低于拒绝阈值，则直接判定为未找到
        if best_candidate and best_candidate[2] < self.max_votes_for_rejection:
            diagnostics['rejection_reason'] = f"最高票数 ({best_candidate[2]}) 低于拒绝阈值 ({self.max_votes_for_rejection})。"
            return None, diagnostics

        if not best_candidate:
            return None, diagnostics

        confidence_report = self._calculate_confidence(
            best_candidate,
            histogram,
            len(query_fingerprints)
        )
        diagnostics['failed_report'] = confidence_report

        is_verified = self._verify_match(confidence_report, histogram)

        if is_verified:
            return confidence_report, diagnostics
        else:
            return None, diagnostics

    def _build_offset_histogram(self, query_fingerprints: List[Tuple[str, int]], db_matches: Dict[str, List[Tuple[int, int]]]) -> Dict:
        """构建时间偏移直方图。"""
        histogram = defaultdict(lambda: defaultdict(int))
        for q_hash, q_time in query_fingerprints:
            if q_hash in db_matches:
                for song_id, db_time in db_matches[q_hash]:
                    offset = db_time - q_time
                    # 时间偏移以秒为单位进行分桶
                    bucket = round(offset / 1000)
                    histogram[song_id][bucket] += 1
        return histogram

    def _detect_peak_match(self, histogram: Dict) -> Optional[Tuple[int, int, int]]:
        """从直方图中识别出票数最高的候选匹配。"""
        candidates = []
        for song_id, buckets in histogram.items():
            if not buckets:
                continue
            max_bucket = max(buckets, key=buckets.get)
            max_votes = buckets[max_bucket]
            if max_votes >= self.min_votes:
                candidates.append((song_id, max_bucket, max_votes))

        if not candidates:
            return None

        candidates.sort(key=lambda x: x[2], reverse=True)

        if len(candidates) > 1:
            if candidates[0][2] / candidates[1][2] >= self.min_ratio:
                return candidates[0]
        elif len(candidates) == 1:
            return candidates[0]

        return None

    def _calculate_confidence(self, best_match: Tuple, histogram: Dict, total_query_hashes: int) -> Dict:
        """
        [已恢复] 使用票数主导的模型计算置信度。
        """
        song_id, offset, votes = best_match

        # 基础票数指标
        total_votes_in_hist = sum(sum(buckets.values()) for buckets in histogram.values())
        if total_votes_in_hist == 0:
            total_votes_in_hist = 1

        # 1. 票数主导的置信度模型 (70%权重)
        # 对数尺度处理，强调高票数的重要性
        vote_score = min(100.0, 100 * (1 - np.exp(-votes / 50)))

        # 2. 辅助指标 (30%权重)
        # 2.1 主峰值占比
        peak_ratio = votes / total_votes_in_hist

        # 2.2 峰值优势比
        other_buckets = [cnt for b, cnt in histogram[song_id].items() if b != offset]
        second_peak_votes = max(other_buckets) if other_buckets else 0
        peak_dominance = votes / (second_peak_votes + 1e-6)

        # 2.3 匹配覆盖率
        if total_query_hashes == 0:
            total_query_hashes = 1
        coverage = votes / total_query_hashes

        # 2.4 时间偏移标准差
        offset_samples = [b for b, count in histogram[song_id].items() for _ in range(count)]
        std_dev = np.std(offset_samples) if len(offset_samples) > 1 else 0.0

        # 辅助指标计算 (归一化处理)
        aux_peak_ratio = min(1.0, peak_ratio * 3)
        aux_peak_dominance = min(1.0, peak_dominance / 10)
        aux_coverage = min(1.0, coverage * 5)
        aux_std_dev = max(0.0, 1.0 - min(1.0, std_dev / 3.0))

        # 辅助指标综合分 (权重共30%)
        aux_score = (
                            0.4 * aux_peak_ratio +
                            0.3 * aux_peak_dominance +
                            0.2 * aux_coverage +
                            0.1 * aux_std_dev
                    ) * 100

        # 最终置信度 = 票数主导(70%) + 辅助指标(30%)
        confidence = 0.7 * vote_score + 0.3 * aux_score

        return {
            'song_id': song_id,
            'offset': offset,
            'confidence': round(confidence, 2),
            'metrics': {
                'vote_score': round(vote_score, 1),
                'peak_ratio': round(peak_ratio, 3),
                'peak_dominance': round(peak_dominance, 2),
                'coverage': round(coverage, 3),
                'std_dev': round(std_dev, 3),
                'votes': votes
            }
        }

    def _verify_match(self, report: Dict, histogram: Dict) -> bool:
        """
        根据阈值配置验证匹配结果的有效性。
        """
        metrics = report['metrics']
        votes = metrics['votes']

        # 1. 超高票数直接通过
        if votes > 10000:
            return True

        # 2. 全局优势检查
        other_song_votes = []
        for song_id, buckets in histogram.items():
            if song_id == report['song_id']:
                continue
            for count in buckets.values():
                other_song_votes.append(count)

        if other_song_votes:
            second_highest_global_vote = max(other_song_votes)
            global_dominance = votes / (second_highest_global_vote + 1e-6)
            if global_dominance > 3.0 and votes > 50:
                return True

        # 3. 置信度检查
        if report['confidence'] < self.thresholds['min_confidence']:
            return False

        # 4. 指标阈值检查
        passed_thresholds = 0
        total_thresholds = 4

        if metrics['peak_ratio'] >= self.thresholds['min_peak_ratio']:
            passed_thresholds += 1
        if metrics['peak_dominance'] >= self.thresholds['min_dominance']:
            passed_thresholds += 1
        if metrics['coverage'] >= self.thresholds['min_coverage']:
            passed_thresholds += 1
        if metrics['std_dev'] <= self.thresholds['max_std_dev']:
            passed_thresholds += 1

        return passed_thresholds >= total_thresholds - 1
